#include <iostream>
#include <unistd.h>
#include <vector>
#include "thread.hpp"

string GetThreadName()
{
    static int number = 1;
    char name[64];
    snprintf(name, sizeof(name), "Thread-%d", number++);
    return name;
}

int ticket = 10000; // 全局的共享资源
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //定义一个锁

//1.我们要尽可能对少的代码加锁(加锁之后基本就是串行了, 如果对大部分代码都加锁, 那么多线程也就没有意义了)
//2.一般加锁，都是给临界区加锁

void GetTicket(string name)
{
    while (true)
    {   
        //1.申请锁本身是安全的, 因为是原子的!
        //2.加锁是有程序员自己保证的! 规则!
        //3.根据互斥的定义, 任何时刻，只允许一个线程申请锁成功! 多个线程申请锁失败, 失败的线程怎么办?? --- 在mutex上阻塞
        //阻塞的本质是等待!
        //4.一个线程在临界区访问临界资源的时候, 可不可能发生线程切换?? 完全可以, 但是仍然没有释放锁，其他线程依旧访问不了临界资源
        //---一个小故事
        //5.加锁的情况下,if里面的代码块也表现出"原子性", 因为这段代码要么不执行，要么执行完，别的线程才能访问
        pthread_mutex_lock(&mutex); 
        if (ticket > 0)
        {
            // 充当抢票花费的时间
            usleep(1000);
            printf("%s get a ticket : %d\n", name.c_str(), ticket);
            ticket--;
            pthread_mutex_unlock(&mutex);
        }
        else
        {
            pthread_mutex_unlock(&mutex);
            break;
        }
        // 实际情况, 还有后续的动作
    }
}

int main()
{
    string name1 = GetThreadName();
    Thread<string> t1(name1, GetTicket, name1);

    string name2 = GetThreadName();
    Thread<string> t2(name2, GetTicket, name2);


    string name3 = GetThreadName();
    Thread<string> t3(name3, GetTicket, name3);

    string name4 = GetThreadName();
    Thread<string> t4(name4, GetTicket, name4);

    t1.start();

    t2.start();

    t3.start();

    t4.start();

    t1.join();
    t2.join();
    t3.join();
    t4.join();
    return 0;
}

